Effective Java 2nd Edition: 2-3章
第2章 オブジェクトの生成と消滅
項目1: static ファクトリーメソッド over コンストラクタ
長所
1. 名前を持つこと
名前で振る舞いについて表現できるようになる
同じ引数シグニチャで異なる意味を持つコンストラクションをしたい時の差別化になる
2. メソッドが呼ばれる度に新しいオブジェクトを作らなくても良いこと
Singleton, Flyweight
ある時点でどのようなインスタンスが存在するかを厳密に制御するのにも使えます
"instance-controlled"
等値性ではなく同一性でもって比較ができる
3. メソッドの返り値にサブタイプを返すことができる
List<T> l1 = Collections.empty() の方が List<T> l2 = new ArrayList<>() よりもインスタンス生成しない分速い
使用する側が実装について知らなくてもよくなる
実際に返すクラスを private にできる
呼び出し毎に条件によって返却するサブクラスを変更できる
4. (Java 7 で消滅)
短所
1. public/protected なコンストラクタを持つサブクラスを作れない
2. 他の static メソッドと区別できない
標準の命名規約に従えば、ある程度予測しやすくなる
項目2: コンストラクタパラメータがいっぱいあったら Builder を検討
Builder pattern
生成されるオブジェクトのクラスを不変にできる
複数種類の可変長引数をとることができる
項目4: private コンストラクタでインスタンス化不可能を強制する
wip
項目5: 不要なオブジェクト生成を避ける
普遍な値は static final
static フィールドは必ず初期化される -> 遅延初期化 (項目71)
実装が複雑になるので本当に必要な時だけにとどめておく
Auto-boxing に注意
項目6: Obsolete Object Reference を破棄する
使われなくなった参照には null を与えておく
使い所
独自のメモリ管理を実装している箇所
キャッシュ
リスナー、コールバック
普通は明示的に登録解除するAPIを用意してそれを使うようにする
第3章 すべてのオブジェクトに共通のメソッド
項目8: equals のオーバーライド -> 一般契約に従う
override
したい時
表現しているものが同じか (同値性) に関心があり、同じインスタンスであるか (同一性) はどうでも良い時 (e.g. 値オブジェクト)
しないのが正しい時
同一性に関心がある時 (e.g. Thread とか)
同値性の検査に関心がない時 (e.g. java.util.Random とか)
スーパークラスの equals() を使うのが適切な時
???
同値関係を表す要素
Reflexive: x.equals(x) == true
Symmetric: x.equals(y) == y.equals(x)
自分と異なるクラスに対してうまく機能できるように実装しないこと
Transitive: IF x.equals(y) == true AND y.equals(z) == true THEN x.equals(z) == true
Consistent: { x != null, y != null } の時、x, y が変更されない限り x.equals(y) の結果は変わらない
Non-nullity: x != null の時、x.equals(null) == false
質の高い equals の実装
==
instanceof
型キャスト
同値性に関わるフィールドを比較
Symmetric, transitive, consistent の3点を満たしているか
IDEに任せよう
補足
引数の型を Object 以外にしてはいけない -> override ではなく overload になる
項目9: equals を override -> hashCode を常に override
hashCode の契約
1つのオブジェクト (?) に割り当てられる hash code は1つだけ
等しいオブジェクトは同じ hash code を持つ
equals で比較した結果が true だったら、それぞれの hash code は等しくなければならない
2つのオブジェクトを equals で比較して false となる場合、それぞれが異なる整数値を返さなければならないという要求はない
でも同値でない時は異なる hash code を返す方が都合が良い
hashCode の override しないと?
Arrays.hashCode
対象クラスが immutable だったら hashCode で返却される値を遅延初期化してキャッシュしても良い
項目10: toString を常に override する
オブジェクトの情報についてわかるように
項目12: Comparable の実装を検討する
compareTo の契約
自身と与えられたオブジェクトを比較して、自身が小さい、等しい、大きいという結果に応じて負の整数、0、正の整数を返却
比較できないオブジェクトを与えられたら ClassCastException
(満たすべき) compareTo の数学的性質
Symmetric: すべての x, y について x.compareTo(y) == -(y.compareTo(x))
Transitive: IF x.compareTo(y) > 0 AND y.compareTo(z) > 0 THEN x.compareTo(z)
すべての z について x.compareTo(y) == 0 ならば、sgn(x.compareTo(z)) == sgn(y.compareTo(z))
sgn(n): n の値が負・0・正に応じて -1, 0, 1 を返却する
(x.compareTo(y) == 0) == x.equals(y) は強く推奨されているが厳密には必須ではない (それぞれ独立しているため)
等値比較と順序比較が独立してて整合性取れていなくて良いというのはヤバイなと思った
Haskell の Eq と Ord みたいな関係 (class Eq a => Ord a where ...) の方がよくない? equals が Object のメソッドとして生えてしまってるので...
equals と異なり継承関係にあるクラスを考慮して実装する必要がない -> ClassCastException を投げる
compareTo の契約に違反した際に影響を受けるもの: TreeSet, TreeMap, Collection, Array, etc...